﻿#region Using Directives

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;

#endregion

namespace Smugmug
{
    public class SmugmugSession : IDisposable
    {
        #region Fields

        private Login login;
        private ILoginMethod loginMethod;
        private SmugmugClient client;

        #endregion

        #region Constructors

        public SmugmugSession(SmugmugClient client, ILoginMethod loginMethod)
        {
            Require.NotNull(client, "client");
            Require.NotNull(loginMethod, "loginMethod");

            this.client = client;
            this.loginMethod = loginMethod;
            EnsureLoggedIn();
        }

        #endregion

        #region Methods

        private void EnsureLoggedIn()
        {
            if (login == null)
                Login();
        }

        public void Logout()
        {
            login = null;
        }

        public void Login()
        {
            login = loginMethod.Login(client);
        }

        #endregion

        #region Properties

        private bool? Pretty
        {
            get { return Config.GetBoolean("Smugmug.Pretty", null); }
        }

        private bool? Strict
        {
            get { return Config.GetBoolean("Smugmug.Strict", null); }
        }

        private string Callback
        {
            get { return Config.GetString("Smugmug.Callback", null); }
        }

        #endregion

        #region Api Methods

        #region Albums

        public void ApplyAlbumWatermark(int albumId, int watermarkId)
        {
            EnsureLoggedIn();
            client.ApplyAlbumWatermark(login.Session.Id, albumId, Callback, Pretty, Strict, watermarkId);
        }

        public IEnumerable<Album> GetAlbums()
        {
            EnsureLoggedIn();
            return client.GetAlbums(login.Session.Id, Callback, null, true, null, null, Pretty, null, Strict);
        }

        public IEnumerable<Album> GetAlbums(string nickName)
        {
            EnsureLoggedIn();
            Require.NotNull(nickName, "nickName");
            return client.GetAlbums(login.Session.Id, Callback, null, true, null, nickName, Pretty, null, Strict);
        }

        public Album GetAlbum(int albumId, string albumKey)
        {
            EnsureLoggedIn();
            return client.GetAlbumInfo(login.Session.Id, albumId, albumKey, Callback, null, Pretty, null, Strict);
        }

        public Album CreateAlbum(Album album)
        {
            EnsureLoggedIn();
            return client.CreateAlbum(login.Session.Id, album, Callback, Pretty, Strict, null);
        }

        public void DeleteAlbum(int albumId)
        {
            EnsureLoggedIn();
            client.DeleteAlbum(login.Session.Id, albumId, null, null, null);
        }

        public AlbumStats GetAlbumStats(int albumId, int month, int year)
        {
            EnsureLoggedIn();
            return client.GetAlbumStats(login.Session.Id, albumId, month, year, true);
        }

        public void RemoveAlbumWatermark(int albumId)
        {
            EnsureLoggedIn();
            client.RemoveAlbumWatermark(login.Session.Id, albumId, Callback, Pretty, Strict);
        }

        public void ReSortAlbum(int albumId)
        {
            EnsureLoggedIn();
            client.ReSortAlbum(login.Session.Id, albumId, Callback, Pretty, Strict);
        }

        public void UpdateAlbumProperty<T>(int albumId, Expression<Func<Album, T>> property, T value)
        {
            EnsureLoggedIn();
            client.ChangeAlbumSetting<T>(login.Session.Id, albumId, property, value, Callback, Pretty, Strict);
        }

        public void UpdateAlbum(Album album)
        {
            EnsureLoggedIn();
            client.ChangeAlbumSettings(login.Session.Id, album, Callback, Pretty, Strict);
        }

        #endregion

        #region Album Templates

        public IEnumerable<AlbumTemplate> GetAlbumTemplates()
        {
            EnsureLoggedIn();
            return client.GetAlbumTemplates(login.Session.Id, Callback, Pretty, Strict);
        }

        public AlbumTemplate CreateAlbumTemplate(AlbumTemplate template)
        {
            EnsureLoggedIn();
            return client.CreateAlbumTemplate(login.Session.Id, template, Callback, Pretty, Strict);
        }

        public void DeleteAlbumTemplate(int albumTemplateId)
        {
            EnsureLoggedIn();
            client.DeleteAlbumTemplate(login.Session.Id, albumTemplateId, Callback, Pretty, Strict);
        }

        public void UpdateAlbumTemplateProperty<T>(int albumTemplateId, Expression<Func<Album, T>> property, T value)
        {
            EnsureLoggedIn();
            client.ChangeAlbumTemplateSetting<T>(login.Session.Id, albumTemplateId, property, value, Callback, Pretty, Strict); ;
        }

        public void UpdateAlbumTemplate(AlbumTemplate template)
        {
            EnsureLoggedIn();
            client.ChangeAlbumTemplateSettings(login.Session.Id, template, Callback, Pretty, Strict);
        }

        #endregion

        #region Categories

        public Category CreateCategory(string name)
        {
            EnsureLoggedIn();
            return client.CreateCategory(login.Session.Id, name, Callback, Pretty, Strict);
        }

        public void DeleteCategory(int categoryId)
        {
            EnsureLoggedIn();
            client.DeleteCategory(login.Session.Id, categoryId, Callback, Pretty, Strict);
        }

        public IEnumerable<Category> GetCategories()
        {
            EnsureLoggedIn();
            return client.GetCategories(login.Session.Id, null, Callback, Pretty, Strict);
        }

        public void UpdateCategory(int categoryId, string name)
        {
            EnsureLoggedIn();
            client.RenameCatgory(login.Session.Id, categoryId, name, Callback, Pretty, Strict);
        }

        #endregion

        #region Communities

        public IEnumerable<Community> GetCommunities()
        {
            EnsureLoggedIn();
            return client.GetCommunities(login.Session.Id, Callback, Pretty, Strict);
        }

        #endregion

        #region Family

        public void AddFamily(string nickname)
        {
            EnsureLoggedIn();
            client.AddFamily(login.Session.Id, nickname, Callback, Pretty, Strict);
        }

        public IEnumerable<Family> GetFamily()
        {
            EnsureLoggedIn();
            return client.GetFamily(login.Session.Id, Callback, Pretty, Strict);
        }

        public void RemoveFamily(string nickname)
        {
            EnsureLoggedIn();
            client.RemoveFamily(login.Session.Id, nickname, Callback, Pretty, Strict);
        }

        public void RemoveAllFamily()
        {
            EnsureLoggedIn();
            client.RemoveAllFamily(login.Session.Id, Callback, Pretty, Strict);
        }

        #endregion

        #region Friends

        public void AddFriend(string nickname)
        {
            EnsureLoggedIn();
            client.AddFriend(login.Session.Id, nickname, Callback, Pretty, Strict);
        }

        public IEnumerable<Friend> GetFriends()
        {
            EnsureLoggedIn();
            return client.GetFriends(login.Session.Id, Callback, Pretty, Strict);
        }

        public void RemoveFriend(string nickname)
        {
            EnsureLoggedIn();
            client.RemoveFriend(login.Session.Id, nickname, Callback, Pretty, Strict);
        }

        public void RemoveAllFriends()
        {
            EnsureLoggedIn();
            client.RemoveAllFriends(login.Session.Id, Callback, Pretty, Strict);
        }

        #endregion

        #region Images

        public void ApplyImageWatermark(int imageId, int watermarkId)
        {
            EnsureLoggedIn();
            client.ApplyImageWatermark(login.Session.Id, imageId, Callback, Pretty, Strict, watermarkId);
        }

        public void ChangeImagePosition(int imageId, int position)
        {
            EnsureLoggedIn();
            client.ChangeImagePosition(login.Session.Id, imageId, position, Callback, Pretty, Strict);
        }

        public void ChangeImageSetting()
        {
            EnsureLoggedIn();
            throw new NotImplementedException();
        }

        public void CropImage()
        {
            EnsureLoggedIn();
            throw new NotImplementedException();
        }

        public void DeleteImage(int imageId)
        {
            EnsureLoggedIn();
            client.DeleteImage(login.Session.Id, imageId, Pretty, Strict);
        }

        public Image GetImageExif(int imageId, string imageKey)
        {
            EnsureLoggedIn();
            return client.GetImageExif(login.Session.Id, imageId, imageKey, Pretty, Strict);
        }

        public Image GetImageInfo(int imageId, string imageKey)
        {
            EnsureLoggedIn();
            return client.GetImageInfo(login.Session.Id, imageId, imageKey, Pretty, Strict);
        }

        public ImageStats GetImageStats(int imageId, int month)
        {
            EnsureLoggedIn();
            throw new NotImplementedException();
        }

        public void GetImagePricing()
        {
            EnsureLoggedIn();
            throw new NotImplementedException();
        }

        public void RotateImage()
        {
            EnsureLoggedIn();
            throw new NotImplementedException();
        }

        public Image UploadImage(string path, int albumId, string albumKey, string caption, string keywords, IUploadProgress callback)
        {
            Require.NotNullOrEmpty(path, "path");
            Require.NotNullOrEmpty(path, "albumKey");
            EnsureLoggedIn();
            return client.UploadImage(login.Session.Id, path, albumId, albumKey, caption, keywords, callback);
        }

        public void UploadImageFromUrl()
        {
            EnsureLoggedIn();
            throw new NotImplementedException();
        }

        public void ZoomImageThumbnail()
        {
            EnsureLoggedIn();
            throw new NotImplementedException();
        }

        public IEnumerable<Image> GetImages(int albumId, string albumKey)
        {
            Require.NotNullOrEmpty(albumKey, "albumKey");
            EnsureLoggedIn();
            return client.GetImages(login.Session.Id, albumId, true, null, null, albumKey);
        }

        public Image GetImageUrls(int imageId, string imageKey)
        {
            Require.NotNullOrEmpty(imageKey, "imageKey");
            EnsureLoggedIn();
            return client.GetImageUrls(login.Session.Id, imageId, TemplateType.Default, null, null, imageKey);
        }

        public void RemoveImageWatermark(int imageId)
        {
            EnsureLoggedIn();
            client.RemoveImageWatermark(login.Session.Id, imageId, Callback, Pretty, Strict);
        }

        #endregion

        #region Products

        public ProductCollection GetProducts()
        {
            EnsureLoggedIn();
            return client.GetProducts(login.Session.Id, Callback, Pretty, Strict);
        }

        #endregion

        #region Pro Pricing

        public IEnumerable<Product> GetAlbumProPricing(int albumId, int? productId, string productType)
        {
            EnsureLoggedIn();
            return client.GetAlbumProPricing(login.Session.Id, albumId, productId, productType, Callback, Pretty, Strict);
        }

        public IEnumerable<Product> GetImageProPricing(int imageId, int? productId, string productType)
        {
            EnsureLoggedIn();
            return client.GetImageProPricing(login.Session.Id, imageId, productId, productType, Callback, Pretty, Strict);
        }

        public IEnumerable<Product> GetPortfollioProPricing(string sessionId, int? productId, string productType, string callback, bool? pretty, bool? strict)
        {
            EnsureLoggedIn();
            return client.GetPortfollioProPricing(login.Session.Id, productId, productType, Callback, Pretty, Strict);
        }

        public void SetAlbumProPricing(int albumId, float price, int? productId, string productType)
        {
            EnsureLoggedIn();
            client.SetAlbumProPricing(login.Session.Id, price, productId, productType, Callback, Pretty, Strict);
        }

        public void SetImageProPricing(int imageId, float price, int? productId, string productType)
        {
            EnsureLoggedIn();
            client.SetImageProPricing(login.Session.Id, imageId, price, productId, productType, Callback, Pretty, Strict);
        }

        public void SetAlbumProPricing(float price, int? productId, string productType)
        {
            EnsureLoggedIn();
            client.SetAlbumProPricing(login.Session.Id, price, productId, productType, Callback, Pretty, Strict);
        }

        #endregion

        #region Share Groups

        public void AddShareGroupAlbum(int shareGroupId, int albumId)
        {
            EnsureLoggedIn();
            client.AddShareGroupAlbum(login.Session.Id, shareGroupId, albumId, Callback, Pretty, Strict);
        }

        public void RemoveShareGroupAlbum(int shareGroupId, int albumId)
        {
            EnsureLoggedIn();
            client.RemoveShareGroupAlbum(login.Session.Id, shareGroupId, albumId, Callback, Pretty, Strict);
        }

        public ShareGroup CreateShareGroup(string name, string description)
        {
            EnsureLoggedIn();
            return client.CreateShareGroup(login.Session.Id, name, description, Callback, Pretty, Strict);
        }

        public void DeleteShareGroup(int shareGroupId)
        {
            EnsureLoggedIn();
            client.DeleteShareGroup(login.Session.Id, shareGroupId, Callback, Pretty, Strict);
        }

        public IEnumerable<Album> GetShareGroupAlbums(string shareGroupTag)
        {
            EnsureLoggedIn();
            return client.GetShareGroupAlbums(login.Session.Id, shareGroupTag, Callback, Pretty, Strict);
        }

        public ShareGroup GetShareGroupInfo(int shareGroupId)
        {
            EnsureLoggedIn();
            return client.GetShareGroupInfo(login.Session.Id, shareGroupId, Callback, Pretty, Strict);
        }

        public IEnumerable<ShareGroup> GetShareGroups()
        {
            EnsureLoggedIn();
            return client.GetShareGroups(login.Session.Id, true, Callback, Pretty, Strict);
        }

        #endregion

        #region Styles

        public IEnumerable<Template> GetStyles()
        {
            EnsureLoggedIn();
            return client.GetStyles(Callback, Pretty, Strict);
        }

        #endregion

        #region Sub Categories

        public Category CreateSubCategory(string name)
        {
            EnsureLoggedIn();
            return client.CreateSubCategory(login.Session.Id, name, Callback, Pretty, Strict);
        }

        public void DeleteSubCategory(int categoryId)
        {
            EnsureLoggedIn();
            client.DeleteSubCategory(login.Session.Id, categoryId, Callback, Pretty, Strict);
        }

        public IEnumerable<Category> GetSubCategories(bool? nickname)
        {
            EnsureLoggedIn();
            return client.GetSubCategories(login.Session.Id, nickname, Callback, Pretty, Strict);
        }

        public void RenameSubCatgory(int categoryId, string name)
        {
            EnsureLoggedIn();
            client.RenameSubCatgory(login.Session.Id, categoryId, name, Callback, Pretty, Strict);
        }

        #endregion

        #region Themes

        public IEnumerable<Theme> GetThemes()
        {
            EnsureLoggedIn();
            return client.GetThemes(login.Session.Id, Callback, Pretty, Strict);
        }

        #endregion

        #region Users

        public User GetUserDisplayName(string nickname)
        {
            EnsureLoggedIn();
            return client.GetUserDisplayName(login.Session.Id, nickname, Callback, Pretty, Strict);
        }

        public UserTree GetUserTree(string nickname, int? lastUpdated)
        {
            EnsureLoggedIn();
            return client.GetUserTree(login.Session.Id, nickname, true, lastUpdated, null, Callback, Pretty, Strict);
        }

        public void GetUserTransferStats(int month, int year)
        {
            throw new NotImplementedException("Method not supported by Smugmug API yet");
            EnsureLoggedIn();
            client.GetUserTransferStats(login.Session.Id, month, year, Callback, Pretty, Strict);
        }

        #endregion

        #endregion

        #region IDisposable Members

        public void Dispose()
        {
            Logout();
        }

        #endregion
    }
}
